package com.gomyb.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author WangTianfu
 * @date 2019/5/14 13:41
 */
@Slf4j
public final class DateUtil {

    /**
     * 锁对象
     */
    private static final Object lockObj = new Object();

    /**
     * 存放不同的日期模板格式的sdf的Map
     */
    private static Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();


    /**
     * 返回一个ThreadLocal的sdf,每个线程只会new一次sdf
     *
     * @param format
     * @return
     */
    private static SimpleDateFormat getSdf(final String format) {
        ThreadLocal<SimpleDateFormat> tl = sdfMap.get(format);

        // 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
        if (tl == null) {
            synchronized (lockObj) {
                tl = sdfMap.get(format);
                if (tl == null) {
                    // 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map
                    // 这里是关键,使用ThreadLocal<SimpleDateFormat>替代原来直接new SimpleDateFormat
                    tl = new ThreadLocal<SimpleDateFormat>() {

                        @Override
                        protected SimpleDateFormat initialValue() {
                            return new SimpleDateFormat(format);
                        }
                    };
                    sdfMap.put(format, tl);
                }
            }
        }

        return tl.get();
    }

    /**
     * 使用ThreadLocal<SimpleDateFormat>来获取SimpleDateFormat,这样每个线程只会有一个SimpleDateFormat
     * 如果新的线程中没有SimpleDateFormat，才会new一个
     *
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, String format) {
        return DateUtil.getSdf(format).format(date);
    }

    /**
     * @Description:
     * @Param: [dateStr, format]
     * @return: java.util.Date
     * @Author: wangtianyong
     * @date: 2019/7/15
     */
    public static Date parse(String dateStr, String format) throws ParseException {
        return DateUtil.getSdf(format).parse(dateStr);
    }


    /**
     * 获取当前周周一日期
     *
     * @return
     */
    public static String getMondayDate() {
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);// 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);// 获得当前日期是一个星期的第几天
        if (dayWeek == 1) {
            dayWeek = 8;
        }

        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);// 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        Date mondayDate = cal.getTime();
        String weekBegin = DateUtil.format(mondayDate, DateFormat.F1);
        return weekBegin;
    }

    /**
     * 获取当前周周日日期
     *
     * @return
     */
    public static String getSundayDate() {
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_WEEK, 7 - cal.get(Calendar.DAY_OF_WEEK) + 1);
        Date sundayDate = cal.getTime();
        String weekEnd = DateUtil.format(sundayDate, DateFormat.F1);

        return weekEnd;
    }

    /**
     * 获取当月第一天日期
     *
     * @return
     */
    public static String getMonthStart() {
        //SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        Date theDate = calendar.getTime();
        GregorianCalendar gcLast = (GregorianCalendar) Calendar.getInstance();
        gcLast.setTime(theDate);
        gcLast.set(Calendar.DAY_OF_MONTH, 1);
        return DateUtil.format(gcLast.getTime(), DateFormat.F1);
    }

    /**
     * 获取本月最后一天
     *
     * @return String
     **/
    public static String getMonthEnd() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        Date time = cal.getTime();
        return DateUtil.format(time, DateFormat.F1);
    }


    /**
     * 日期转化为cron表达式
     */
    public static String getCron(java.util.Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        return DateUtil.fmtDateToStr(date, dateFormat);
    }

    /**
     * cron表达式转为日期
     */
    public static Date getCronToDate(String cron) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        Date date = null;
        try {
            date = DateUtil.parse(cron, dateFormat);
        } catch (ParseException e) {
            log.error(e.toString());
            return null;
        }
        return date;
    }

    /**
     * Description:格式化日期,String字符串转化为Date
     */
    public static String fmtDateToStr(Date date, String dtFormat) {
        if (date == null)
            return "";
        try {
            return DateUtil.format(date, dtFormat);
        } catch (Exception e) {
            log.error(e.toString());
            return "";
        }
    }

    /**
     * 获取当前系统前后几天的时间
     * +n  new Date() + n 天
     * -n new Date() - n 天
     *
     * @return
     */
    public static String getDayTime(final String dtFormat, int day) {
        Date date = new Date();
        if (day == 0) {
            return DateUtil.format(date, dtFormat);
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        date = calendar.getTime();
        return DateUtil.format(date, dtFormat);
    }

    /**
     * 获取系统前后几周前的时间
     * +n  new Date() + n 周
     * -n new Date() - n 周
     *
     * @return
     */
    public static String getWeakTime(final String dtFormat, int week) {
        Date date = new Date();
        if (week == 0) {
            return DateUtil.format(date, dtFormat);
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.WEEK_OF_YEAR, week);
        date = calendar.getTime();
        return DateUtil.format(date, dtFormat);
    }

    /**
     * @Description: 获取一段时间的每一天
     * @Param:
     * @return:
     * @Author: wangtianyong
     * @date:
     */
    public static List<String> getEveryDay(String dateStart, String dateEnd) {
        List<String> dateList = new ArrayList<String>();
        try {
            Date dateOne = DateUtil.parse(dateStart, DateFormat.F1);
            Date dateTwo = DateUtil.parse(dateEnd, DateFormat.F1);
            Calendar cal = Calendar.getInstance();
            cal.setTime(dateOne);
            while (cal.getTime().compareTo(dateTwo) < 0) {
                cal.add(Calendar.DAY_OF_MONTH, 1);
                dateList.add(DateUtil.format(cal.getTime(), DateFormat.F1));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dateList;
    }

    /**
     * @Description: 获取 自定义 据endDay 前后几天的 日期
     * @Param:
     * @return:
     * @Author: wangtianyong
     * @date:
     */
    public static String getCustomizeDate(DateUtilCustomizeEnum type, String endDay, int i, String format) {
        Date dateNow = null;
        if (StringUtils.isEmpty(endDay)) {
            dateNow = new Date();
        } else {
            try {
                dateNow = DateUtil.parse(endDay, format);
            } catch (Exception e) {
                e.printStackTrace();
                log.error(e.toString());
                dateNow = new Date();
            }
        }
        Calendar cl = Calendar.getInstance();
        cl.setTime(dateNow);
        switch (type) {
            case DAY:
                cl.add(Calendar.DAY_OF_YEAR, i);
                break;
            case WEEK:
                cl.add(Calendar.WEEK_OF_YEAR, i);
                break;
            case YEAR:
                cl.add(Calendar.YEAR, i);
                break;
            case MONTH:
                cl.add(Calendar.MONTH, i);
                break;
            case MINUTE:
                cl.add(Calendar.MINUTE, i);
        }
        String day = DateUtil.format(cl.getTime(), format);
        return day;
    }

    /**
     * @Description: 获取时间间隔为 days 的日期 循环 cycle 次  过去时间传-n  未来时间传+n
     * @Param:
     * @return:
     * @Author: wangtianyong
     * @date:
     */
    public static List<String> getDayCycleList(DateUtilCustomizeEnum type, String startDay, Integer days, Integer cycle, String format) {
        if (cycle <= 0) {
            return null;
        }
        List<String> dayList = new ArrayList<>(cycle);
        dayList.add(startDay);
        for (int i = 0; i < cycle; i++) {
            String customizeDate = DateUtil.getCustomizeDate(type, startDay, days, format);
            startDay = customizeDate;
            dayList.add(customizeDate);
        }
        return dayList;
    }

    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致
     *
     * @param nowTime   当前时间
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return boolean
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime == null) {
            return false;
        }

        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    public class DateFormat {
        public static final String F1 = "yyyy-MM-dd";
        public static final String F2 = "EEEE";
        public static final String F3 = "yyyy-MM-dd HH:mm:ss";
    }

    public static void main(String[] args) {
        try {
            Date parse = DateUtil.parse(null + " 00:00:00", DateFormat.F3);
            Date parse1 = DateUtil.parse(null + " 23:59:59", DateFormat.F3);
            System.out.println(parse + "++++++++" + "parse1");
        } catch (Exception e) {

        }
    }
}
